#include "app_message.h"
#include <string.h>
#include <stdlib.h>
#include "thirdparty/log.c/log.h"
#include "thirdparty/cJSON/cJSON.h"

/**
 * @brief 将字符串反序列化为二进制字符串
 *
 * @param str
 * @param buf
 * @param len
 * @return int 成功返回长度 -1失败
 */
static int app_message_strToBin(char *str, void *buf, int len)
{
    unsigned char *ptr = buf;
    int str_len = strlen(str);
    if (str_len % 2 != 0 || str_len / 2 > len)
    {
        return -1;
    }

    for (int i = 0; i < str_len / 2; i++)
    {
        ptr[i] = 0;
        for (int j = 0; j < 2; j++)
        {
            ptr[i] <<= 4;
            if (str[i * 2 + j] >= '0' && str[i * 2 + j] <= '9')
            {
                ptr[i] |= str[i * 2 + j] - '0';
            }
            else
            {
                ptr[i] |= str[i * 2 + j] - 'A' + 10;
            }
        }
    }

    return str_len / 2;
}

/**
 * @brief 将二进制序列化为字符串，用完需要释放
 */
static char *app_message_binToStr(void *buf, int len)
{
    char dict[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    unsigned char *ptr = buf;
    char *result = malloc(len * 2 + 1);
    if (!result)
    {
        return NULL;
    }
    for (int i = 0; i < len; i++)
    {
        unsigned char temp = ptr[i];
        for (int j = 1; j >= 0; j--)
        {
            result[i * 2 + j] = dict[temp & 0x0F];
            temp >>= 4;
        }
    }
    result[len * 2] = 0;
    return result;
}

int app_message_initByBinary(Message *message, ConnectionType connection_type, void *buf, int len)
{
    log_trace("app_message_initByBinary: enter");
    unsigned char *ptr = buf;

    if (ptr[0] + ptr[1] + 2 > len)
    {
        log_warn("Message binary not valid.");
        return -1;
    }

    // 申请消息指针内存
    message->ptr = malloc(ptr[0] + ptr[1]);
    if (!message->ptr)
    {
        log_warn("Not enough for memory, malloc length: %d", ptr[0] + ptr[1]);
        return -1;
    }
    message->id_len = ptr[0];
    message->msg_len = ptr[1];
    message->connection_type = connection_type;

    // 将剩余的二进制全部拷贝出来
    memcpy(message->ptr, ptr + 2, ptr[0] + ptr[1]);
    log_trace("app_message_initByBinary: leave");
    return 0;
}

int app_message_initByJsonStr(Message *message, char *json_str)
{
    log_trace("app_message_initByJsonStr: enter");
    // 解析Json string
    cJSON *json_obj = cJSON_Parse(json_str);
    if (!json_obj)
    {
        log_warn("Not a valid json string");
        goto CJSON_FAIL;
    }

    cJSON *connection_type_json = cJSON_GetObjectItem(json_obj, "connection_type");
    cJSON *id_json = cJSON_GetObjectItem(json_obj, "id");
    cJSON *msg_json = cJSON_GetObjectItem(json_obj, "message");

    // 判断字符串合法性
    char *id_str = id_json->valuestring;
    char *msg_str = msg_json->valuestring;
    int id_len = strlen(id_str);
    int msg_len = strlen(msg_str);
    if (id_len % 2 != 0 || msg_len % 2 != 0)
    {
        log_warn("Json data not valid: %s", json_str);
        goto CJSON_FAIL;
    }

    // 申请消息指针
    message->ptr = malloc(id_len / 2 + msg_len / 2);
    if (!message->ptr)
    {
        log_warn("Not enough for memory, malloc length: %d", id_len / 2 + msg_len / 2);
        goto CJSON_FAIL;
    }

    // 反序列化id
    if (app_message_strToBin(id_str, message->ptr, id_len / 2) < 0)
    {
        log_warn("Json data not valid: %s", json_str);
        goto BINARY_FAIL;
    }
    message->id_len = id_len / 2;

    // 反序列化msg
    if (app_message_strToBin(msg_str, message->ptr + message->id_len, msg_len / 2) < 0)
    {
        log_warn("Json data not valid: %s", json_str);
        goto BINARY_FAIL;
    }
    message->msg_len = msg_len / 2;

    // 反序列号conn_type
    message->connection_type = (unsigned char)connection_type_json->valueint;

    cJSON_free(json_obj);
    log_trace("app_message_initByJsonStr: leave");
    return 0;

BINARY_FAIL:
    app_message_free(message);
CJSON_FAIL:
    // 释放JSON String
    cJSON_free(json_obj);
    log_trace("app_message_initByJsonStr: leave");
    return -1;
}

int app_message_saveBinary(Message *message, void *buf, int len)
{
    log_trace("app_message_saveBinary: enter");
    // 首先储存id和msg长度
    unsigned char *ptr = buf;
    if (len < message->id_len + message->msg_len + 2)
    {
        log_warn("Buff not enough!");
        return -1;
    }

    ptr[0] = message->id_len;
    ptr[1] = message->msg_len;

    memcpy(ptr + 2, message->ptr, ptr[0] + ptr[1]);
    log_trace("app_message_saveBinary: leave");
    return ptr[0] + ptr[1] + 2;
}

int app_message_saveJson(Message *message, char *json_buf, int len)
{
    log_trace("app_message_saveJson: enter");
    cJSON *json_obj = cJSON_CreateObject();
    if (!json_obj)
    {
        log_warn("Not enough memory for Json obj");
        return -1;
    }

    // 添加类型
    cJSON_AddNumberToObject(json_obj, "connection_type", message->connection_type);
    // 添加ID
    cJSON_AddStringToObject(json_obj, "id", app_message_binToStr(message->ptr, message->id_len));
    // 添加msg
    cJSON_AddStringToObject(json_obj, "message", app_message_binToStr(message->ptr + message->id_len, message->msg_len));

    char *str = cJSON_PrintUnformatted(json_obj);
    if (!str)
    {
        log_warn("Not enough memory for Json str");
        cJSON_free(json_obj);
        return -1;
    }

    int str_len = strlen(str);

    if (len <= str_len)
    {
        log_warn("Buffer len not enough");
        free(str);
        cJSON_free(json_obj);
        return -1;
    }
    memcpy(json_buf, str, str_len + 1);

    free(str);
    cJSON_free(json_obj);
    log_trace("app_message_saveJson: leave");
    return 0;
}

void app_message_free(Message *message)
{
    if (message->ptr)
    {
        free(message->ptr);
        message->ptr = NULL;
    }
}
